import Button from '../ui/Button';
import OutsideClickHandler from 'react-outside-click-handler';
import React, { useState } from 'react';
import saveAs from 'file-saver';
import showModalWithInput from './ModalWithInput';
import styles from './ExportData.module.scss';
import {
  convertPresetsToDate,
} from '../util/formatDate';
import { faShareSquare } from '@fortawesome/free-solid-svg-icons/faShareSquare';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { format } from 'date-fns';
import { isRouteActive, ROUTES } from '../pages/routes';
import { Profile } from '../models';
import { Tooltip } from '../ui/Tooltip';
import { useLocation } from 'react-router-dom';
import { FlamegraphRenderer } from '../flamegraph';
import ReactDOMServer from 'react-dom/server';
import 'compression-streams-polyfill';

/* eslint-disable react/destructuring-assignment */

// These are modeled individually since each condition may have different values
// For example, a exportPprof: true may accept a custom export function
// For cases like grafana
type exportJSON = {
  exportJSON?: boolean;
  flamebearer: Profile;
};

// type exportPprof = {
//   exportPprof?: boolean;
//   flamebearer: Profile;
// };

type exportHTML = {
  exportHTML?: boolean;
  fetchUrlFunc?: () => string;
  flamebearer: Profile;
};

// type exportFlamegraphDotCom = {
//   exportFlamegraphDotCom?: boolean;
//   exportFlamegraphDotComFn?: (name?: string) => Promise<string | null>;
//   flamebearer: Profile;
// };

type exportPNG = {
  exportPNG?: boolean;
  flamebearer: Profile;
};

// export class PprofRequest extends Message<PprofRequest> {
//   constructor(
//     profile_typeID: string,
//     label_selector: string,
//     start: number,
//     end: number
//   ) {
//     super();
//     this.profile_typeID = profile_typeID;
//     this.label_selector = label_selector;
//     this.start = start;
//     this.end = end;
//   }

//   @Field.d(1, 'string')
//   profile_typeID: string;

//   @Field.d(2, 'string')
//   label_selector: string;

//   @Field.d(3, 'int64')
//   start: number;

//   @Field.d(4, 'int64')
//   end: number;
// }

export type ExportDataProps = {
  buttonEl?: React.ComponentType<{
    onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
  }>;
} & 
  // exportPprof &
  exportHTML &
  // exportFlamegraphDotCom &
  exportPNG &
  exportJSON;


// function buildPprofQuery(state: ContinuousState) {
//   const { from, until } = biggestTimeRangeInUnixMs(state);
//   const labelsIndex = state.query.indexOf('{');
//   const profileTypeID = state.query.substring(0, labelsIndex);
//   const label_selector = state.query.substring(labelsIndex);
//   const message = new PprofRequest(profileTypeID, label_selector, from, until);
//   return PprofRequest.encode(message).finish();
// }

function ExportData(props: ExportDataProps) {
  // exportFlamegraphDotCom = true
  const { exportJSON = false } = props;
  // let { exportPprof } = props;
  const exportPNG = true;
  const exportHTML = true;
  const { pathname } = useLocation();
  // const dispatch = useAppDispatch();
  // const pprofQuery = useAppSelector((state: { continuous: ContinuousState }) =>
  //   buildPprofQuery(state.continuous)
  // );

  if (
    isRouteActive(pathname, ROUTES.COMPARISON_DIFF_VIEW) ||
    isRouteActive(pathname, ROUTES.COMPARISON_VIEW)
  ) {
    // exportPprof = false;
  }
  if (
    !exportPNG &&
    !exportJSON &&
    // !exportPprof &&
    !exportHTML 
    // !exportFlamegraphDotCom
  ) {
    throw new Error('At least one export button should be enabled');
  }

  const [toggleMenu, setToggleMenu] = useState(false);

  const downloadJSON = async () => {
    if (!props.exportJSON) {
      return;
    }

    // TODO additional check this won't be needed once we use strictNullChecks
    if (props.exportJSON) {
      const { flamebearer } = props;

      const defaultExportName = getFilename(
        flamebearer.metadata.appName,
        flamebearer.metadata.startTime,
        flamebearer.metadata.endTime
      );
      // get user input from modal
      const customExportName = await getCustomExportName(defaultExportName);
      // return if user cancels the modal
      if (!customExportName) {
        return;
      }

      const filename = `${customExportName}.json`;

      const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(
        JSON.stringify(flamebearer)
      )}`;

      saveAs(dataStr, filename);
    }
  };

  // const downloadFlamegraphDotCom = async () => {
  //   if (!exportFlamegraphDotCom) {
  //     return;
  //   }

  //   const { flamebearer } = props;

  //   const defaultExportName = getFilename(
  //     flamebearer.metadata.appName,
  //     flamebearer.metadata.startTime,
  //     flamebearer.metadata.endTime
  //   );
  //   // get user input from modal
  //   const customExportName = await getCustomExportName(defaultExportName);
  //   // return if user cancels the modal
  //   if (!customExportName) {
  //     return;
  //   }

  //   const url = await flameGraphUpload(customExportName, flamebearer);
  //   if (url.isErr) {
  //     handleError(dispatch, 'Failed to export to flamegraph.com', url.error);
  //     return;
  //   }

  //   const dlLink = document.createElement('a');
  //   dlLink.target = '_blank';
  //   dlLink.href = url.value;

  //   document.body.appendChild(dlLink);
  //   dlLink.click();
  //   document.body.removeChild(dlLink);
  // };

  const downloadPNG = async () => {
    if (exportPNG) {
      const { flamebearer } = props;

      const defaultExportName = getFilename(
        flamebearer.metadata.appName,
        flamebearer.metadata.startTime,
        flamebearer.metadata.endTime
      );
      // get user input from modal
      const customExportName = await getCustomExportName(defaultExportName);
      // return if user cancels the modal
      if (!customExportName) {
        return;
      }

      const filename = `${customExportName}.png`;

      // TODO use ref
      // this won't work for comparison side by side
      const canvasElement = document.querySelector(
        '.flamegraph-canvas'
      ) as HTMLCanvasElement;
      canvasElement.toBlob(function (blob) {
        if (!blob) {
          return;
        }
        saveAs(blob, filename);
      });
    }
  };

  const handleToggleMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
    event.preventDefault();
    setToggleMenu(!toggleMenu);
  };

  // const downloadPprof = async function () {
  //   if (!exportPprof) {
  //     return;
  //   }

  //   if (props.exportPprof) {
  //     // get user input from modal
  //     const customExportName = await getCustomExportName('profile.pb.gz');
  //     // return if user cancels the modal
  //     if (!customExportName) {
  //       return;
  //     }
  //     const response = await downloadWithOrgID(
  //       '/querier.v1.QuerierService/SelectMergeProfile',
  //       {
  //         headers: {
  //           'content-type': 'application/proto',
  //         },
  //         method: 'POST',
  //         body: pprofQuery,
  //       }
  //     );
  //     if (response.isErr) {
  //       handleError(dispatch, 'Failed to export to pprof', response.error);
  //       return;
  //     }
  //     const data = await new Response(
  //       response.value.body?.pipeThrough(new CompressionStream('gzip'))
  //     ).blob();
  //     saveAs(data, customExportName);
  //   }
  // };

  const downloadHTML = async () => {
    if (exportHTML) {
      const { flamebearer } = props;
  
      const defaultExportName = getFilename(
        flamebearer.metadata.appName,
        flamebearer.metadata.startTime,
        flamebearer.metadata.endTime
      );
      const customExportName = await getCustomExportName(defaultExportName);
      if (!customExportName) {
        return;
      }
      const SimpleTree = {
        version: 1,
        flamebearer: {
          names: [
            'total',
            'runtime.mcall',
            'runtime.park_m',
            'runtime.schedule',
            'runtime.resetspinning',
            'runtime.wakep',
            'runtime.startm',
            'runtime.notewakeup',
            'runtime.semawakeup',
            'runtime.pthread_cond_signal',
            'runtime.findrunnable',
            'runtime.netpoll',
            'runtime.kevent',
            'runtime.main',
            'main.main',
            'github.com/pyroscope-io/client/pyroscope.TagWrapper',
            'runtime/pprof.Do',
            'github.com/pyroscope-io/client/pyroscope.TagWrapper.func1',
            'main.main.func1',
            'main.slowFunction',
            'main.slowFunction.func1',
            'main.work',
            'runtime.asyncPreempt',
            'main.fastFunction',
            'main.fastFunction.func1',
          ],
          levels: [
            [0, 609, 0, 0],
            [0, 606, 0, 13, 0, 3, 0, 1],
            [0, 606, 0, 14, 0, 3, 0, 2],
            [0, 606, 0, 15, 0, 3, 0, 3],
            [0, 606, 0, 16, 0, 1, 0, 10, 0, 2, 0, 4],
            [0, 606, 0, 17, 0, 1, 0, 11, 0, 2, 0, 5],
            [0, 606, 0, 18, 0, 1, 1, 12, 0, 2, 0, 6],
            [0, 100, 0, 23, 0, 506, 0, 19, 1, 2, 0, 7],
            [0, 100, 0, 15, 0, 506, 0, 16, 1, 2, 0, 8],
            [0, 100, 0, 16, 0, 506, 0, 20, 1, 2, 2, 9],
            [0, 100, 0, 17, 0, 506, 493, 21],
            [0, 100, 0, 24, 493, 13, 13, 22],
            [0, 100, 97, 21],
            [97, 3, 3, 22],
          ],
          numTicks: 609,
          maxSelf: 493,
        },
        metadata: {
          // appName: 'simple.golang.app.cpu',
          // name: 'simple.golang.app.cpu 2022-09-06T12:16:31Z',
          // startTime: 1662466591,
          // endTime: 1662470191,
          // query: 'simple.golang.app.cpu{}',
          // maxNodes: 1024,
          format: 'single' as const,
          sampleRate: 100,
          spyName: 'gospy' as const,
          units: 'samples' as const,
        },
      };
      const filename = `${customExportName}.html`;
      // const canvasElement = document.querySelector('.flamegraph-canvas') as HTMLCanvasElement;
      const htmlString = ReactDOMServer.renderToString(<FlamegraphRenderer  profile={SimpleTree} />)
      saveAs(htmlString, filename);
    }
  };
  
  async function getCustomExportName(defaultExportName: string) {
    return showModalWithInput({
      title: 'Enter export name',
      confirmButtonText: 'Export',
      input: 'text',
      inputValue: defaultExportName,
      inputPlaceholder: 'Export name',
      type: 'normal',
      validationMessage: 'Name must not be empty',
      onConfirm: (value: any) => value, // ShamefulAny
    });
  }

  return (
    <div className={styles.dropdownContainer}>
      <OutsideClickHandler onOutsideClick={() => setToggleMenu(false)}>
        {props.buttonEl ? (
          <props.buttonEl onClick={handleToggleMenu} />
        ) : (
          <Tooltip placement="top" title="Export Data">
            <Button
              className={styles.toggleMenuButton}
              onClick={handleToggleMenu}
            >
              <FontAwesomeIcon icon={faShareSquare} />
            </Button>
          </Tooltip>
        )}
        <div className={toggleMenu ? styles.menuShow : styles.menuHide}>
          {exportPNG && (
            <button
              className={styles.dropdownMenuItem}
              onClick={downloadPNG}
              onKeyPress={downloadPNG}
              type="button"
            >
              png
            </button>
          )}
          {exportJSON && (
            <button
              className={styles.dropdownMenuItem}
              type="button"
              onClick={downloadJSON}
            >
              json
            </button>
          )}
          {/* {exportPprof && (
            <button
              className={styles.dropdownMenuItem}
              type="button"
              onClick={downloadPprof}
            >
              pprof
            </button>
          )} */}
          {exportHTML && (
            <button
              className={styles.dropdownMenuItem}
              type="button"
              onClick={downloadHTML}
            >
              {' '}
              html
            </button>
          )}
          {/* {exportFlamegraphDotCom && (
            <button
              className={styles.dropdownMenuItem}
              type="button"
              onClick={downloadFlamegraphDotCom}
            >
              {' '}
              flamegraph.com
            </button>
          )} */}
        </div>
      </OutsideClickHandler>
    </div>
  );
}

const dateFormat = 'yyyy-MM-dd_HHmm';

function dateForExportFilename(from: string, until: string) {
  let start = new Date(Math.round(parseInt(from, 10) * 1000));
  let end = new Date(Math.round(parseInt(until, 10) * 1000));

  if (/^now-/.test(from) && until === 'now') {
    const { _from } = convertPresetsToDate(from);

    start = new Date(Math.round(parseInt(_from.toString(), 10) * 1000));
    end = new Date();
  }

  return `${format(start, dateFormat)}-to-${format(end, dateFormat)}`;
}

export function getFilename(
  appName?: string,
  startTime?: number,
  endTime?: number
) {
  //  const appname = flamebearer.metadata.appName;
  let date = '';

  if (startTime && endTime) {
    date = dateForExportFilename(startTime.toString(), endTime.toString());
  }

  // both name and date are available
  if (appName && date) {
    return [appName, date].join('_');
  }

  // only fullname
  if (appName) {
    return appName;
  }

  // only date
  if (date) {
    return ['flamegraph', date].join('_');
  }

  // nothing is available, use a generic name
  return `flamegraph`;
}

export default ExportData;
